Spring 支持 Restful风格 源码分析
Restful风格API接口开发springMVC -- json
Restful 请求处理 和 响应
RequestResponseBodyMethodProcessor
return parameter.hasParameterAnnotation(RequestBody.class); //解析方法-属性带有@RequestBody的参数
for (HttpMessageConverter<?> converter : this.messageConverters) { } //遍历所有的消息转换器,包括我们自定义的
this.messageConverters // 在什么时候初始化的??
AnnotationMethodHandlerAdapter -- RequestMappingHandlerAdapter //配置文件 -- 实际操作的
RequestMappingHandlerAdapter.afterPropertiesSet() //由于RequestMappingHandlerAdapter实现InitializingBean接口,
所以容器初始化时(启动的时候) 就会去执行这个方法,完成一些初始化的工作
RequestMappingHandlerAdapter.getDefaultArgumentResolvers() //完成如下一些参数解析器类的初始化
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ServletModelAttributeMethodProcessor(false));
resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters()));
resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters()));
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new HttpEntityMethodProcessor(getMessageConverters()));
resolvers.add(new RedirectAttributesMethodArgumentResolver());
resolvers.add(new ModelMethodProcessor());
resolvers.add(new MapMethodProcessor());
resolvers.add(new ErrorsMethodArgumentResolver());
resolvers.add(new SessionStatusMethodArgumentResolver());
resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter //同时该类还继承
private List<HttpMessageConverter<?>> messageConverters; //且有成员变量消息转换器的list集合
//并完成默认构造器来注册默认的消息转换器
public RequestMappingHandlerAdapter() {
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
stringHttpMessageConverter.setWriteAcceptCharset(false); // See SPR-7316
this.messageConverters = new ArrayList<HttpMessageConverter<?>>();
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(stringHttpMessageConverter);
this.messageConverters.add(new SourceHttpMessageConverter<Source>());
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
}
//而对应自定义的AnnotationMethodHandlerAdapter 依赖的MappingJacksonHttpMessageConverter,通过xml文件的解析可以将消息转换器注册到RequestMappingHandlerAdapter
//判断给定的类是否可以由这个转换器读取。
if (converter.canRead(targetClass, contentType)) {
//使用这个消息转换器去转换
return ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage);
}
StringHttpMessageConverter //String请求的消息转换器
//去解析处理clazz:是一个String的类型,inputMessage:是一个请求输入流的类型
StringHttpMessageConverter{return readInternal(clazz, inputMessage);}
//把HttpRequest请求参数解析成一个StringBuilder,并返回
return StreamUtils.copyToString(inputMessage.getBody(), charset);
//回去socket请求的输入流,解析输入流于StringBuilder,并返回给调用者
public static String copyToString(InputStream in, Charset charset) throws IOException {
Assert.notNull(in, "No InputStream specified");
StringBuilder out = new StringBuilder();
InputStreamReader reader = new InputStreamReader(in, charset);
char[] buffer = new char[BUFFER_SIZE];
int bytesRead = -1;
while ((bytesRead = reader.read(buffer)) != -1) {
out.append(buffer, 0, bytesRead);
}
return out.toString();
}
//前台请求虽然有多个消息转换器,但实际就只有一个去处理请求,StringHttpMessageConverter,所以我们经常说前后台交互就是String类型
//当StringHttpMessageConverter处理完了就直接返回处理结果了,就不会再执行别的消息转换器了
//所以在controller配置入参转换器是没有意义的,如:@ResponeBody String param,是体现不了json转换器的
//拿到通过请求参数数组args来调用具体Method的invok(),调用成功后返回调用结果,returnValue为值
ServletInvocableHandlerMethod.invokeAndHandle(){ Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);}
//如:public Map | String | List xxx 代表了请求后响应也对应了有多种情况,对应各种类型
//处理返回值,也对应了返回值类型的装换
HandlerMethodReturnValueHandlerComposite.handleReturnValue()
//还是对应了Handler来处理返回值,还是采用相同的策略模式来处理
HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType);
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
//这是RequestMappingHandlerAdapter在初始化的时候所注册的一些实例,就包括了方法参数解析器和方法返回参数解析器相关类的初始化
public void afterPropertiesSet() {
if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
initControllerAdviceCache();
}
//当返回值是String类型的,对应的HandlerMethodReturnValueHandler就会去处理对应返回类型
//将返回值包装到ModelAndViewContainer容器中
ViewNameMethodReturnValueHandler.handleReturnValue(){ //其中ModelAndViewContainer mavContainer
else if (returnValue instanceof String) {
String viewName = (String) returnValue;
mavContainer.setViewName(viewName); //返回的值就是一个视图的名称,就是一个具体的页面,
if (isRedirectViewName(viewName)) {
mavContainer.setRedirectModelScenario(true);
}
}
//这个方法是支持@ResponeBody Map | String | List 以json类型返回的调用方法
RequestResponseBodyMethodProcessor.handleReturnValue(){
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException {
mavContainer.setRequestHandled(true); //*****很重要
if (returnValue != null) {
writeWithMessageConverters(returnValue, returnType, webRequest);
}
}
}
//遍历消息转换器
for (HttpMessageConverter<?> messageConverter : messageConverters) { //和入参使用的消息转换器是一致的
//判断是否写
if (messageConverter.canWrite(returnValueClass, selectedMediaType)) {
//使用消息转换器回写给调用者
((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage);
return;
}
}
//创建ServletServerHttpRequest和ServletServerHttpResponse
AbstractMessageConverterMethodProcessor.writeWithMessageConverters(T returnValue, //调用方法返回的值,如string | "5555" map | "name:55"
MethodParameter returnType, //HandlerMethodReturnValueHandler
NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException {
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
//object:是调用方法后的返回值 outputMessage:HttpOutputMessage 响应值
MappingJacksonHttpMessageConverter.writeInternal(Object object, HttpOutputMessage outputMessage)
//调用jackson api
this.objectMapper.writeValue(jsonGenerator, object);
//调用jackson api后将调用后的数据刷入outputMessage实体中(相当于给调用者的返回)
writeInternal(t, outputMessage);
outputMessage.getBody().flush();
//重要,负者参数的解析和参数的返回
RequestMappingHandlerAdapter.invokeAndHandle(){
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);//参数解析***
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(this.responseReason)) {
mavContainer.setRequestHandled(true); //请求类别***
return;
}
mavContainer.setRequestHandled(false);
try {
//参数返回***
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
}
//很重要** 相当于包装成ModelAndView返回给调用者
return RequestMappingHandlerAdapter.getModelAndView(mavContainer, modelFactory, webRequest);
//获取视图和实体信息
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
modelFactory.updateModel(webRequest, mavContainer);
if (mavContainer.isRequestHandled()) { //当为@ResponeBody的时候为true,就直接返回给了数据,没有返回对应的页面
return null;
}
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model); // 构造视图响应
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
return mav;
}
//在此之前已经完成了ModelAndView实体的构建,接下来要完成视图的解析和渲染
DispatcherServlet.processDispatchResult() //进程调度的结果
{
render(mv, request, response); //渲染
}
// 解析视图
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
// 遍历所有的视图解析器去解析视图,如internalResolverView
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale); //viewName : 就是对应的返回页面
if (view != null) {
return view;
}
}
InternalResourceView.renderMergedOutputModel(){
// 确定请求调度程序的路径。如:WEB-INFO/index.jsp
String dispatcherPath = prepareForRendering(requestToExpose, response);
//为目标资源获取一个RequestDispatcher(通常是一个JSP)。
RequestDispatcher rd = getRequestDispatcher(requestToExpose, dispatcherPath);
}
RequestDispatcher //就相当于一个servlet
rd.forward(requestToExpose, response); //可以做相应的转发工作,转发到一个页面
mappedHandler.triggerAfterCompletion(request, response, null); //接着调用后置过滤器
MappingJacksonHttpMessageConverter 的定义的作用,如果在配置文件中没有定义消息转换器,并且spring也没给你做消息转换
这样在controller中使用@ResponeBody 是不支持Restful - json 风格的响应的
//在实际返回值的时候是交给具体的自定义messageConverters消息转换器来转换的,不注册这个消息装换器是无法正常解析给调用者返回值的json
for (HttpMessageConverter<?> messageConverter : messageConverters) {
if (messageConverter.canWrite(returnValueClass, selectedMediaType)) {
((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage);
if (logger.isDebugEnabled()) {
logger.debug("Written [" + returnValue + "] as \"" + selectedMediaType + "\" using [" +
messageConverter + "]");
}
return;
}
}
//不加这个MappingJacksonHttpMessageConverter 是无法直接支持restful - json格式的
//处理给前端返回map,list,string 还可以直接返回一个实体,这个实体可以用@ResponeBody+配置json装换器,来让它支持restful的响应